今天要來介紹,如何用 golang 做一個 webosocket server 的相關應用。我個人沒有使用 golang 原生的 webscoket,而是用我前面一直有介紹到的 gorilla 團隊做的 gorilla/websocket,
他一樣有符合我的原則,而且沒有太多的依賴,非常適合拿來當個應用的基礎 package 。
在開始介紹如何寫 websocket 之前,我們還是簡單科普一下 websocket 到底是什麼?
WebSocket是一種在單個TCP連接上進行全雙工通訊的協定。WebSocket通訊協定於2011年被IETF定為標準RFC 6455,並由RFC7936補充規範。WebSocket API也被W3C定為標準。
WebSocket使得用戶端和伺服器之間的資料交換變得更加簡單,允許伺服器端主動向用戶端推播資料。在WebSocket API中,瀏覽器和伺服器只需要完成一次交握,兩者之間就直接可以建立永續性的連接,並進行雙向資料傳輸。
由 wiki 摘錄上面的段話,可以把它想像成類似 socket 協定的東西,只是 websocket 是基於 http 之上的協定,但兩者最終都還是 TCP 之上的東西。運用這個特性,大家在 web 上想要實現即時的推播,就不需要使用輪詢等相關技術,減少 http request 相關檔頭肥大的問題。 剩下更詳細的介紹就請到 wiki 閱讀了。
接下來我們來介紹,如何運用 gorilla/websocket 寫一個簡單的 client / server 的應用
在開發之前,請記得下
go get github.com/gorilla/websocket
才有辦法執行下面範例,以及對應開發需求喔
func main() {
upgrader := &websocket.Upgrader{
//如果有 cross domain 的需求,可加入這個,不檢查 cross domain
CheckOrigin: func(r *http.Request) bool { return true },
}
http.HandleFunc("/echo", func(w http.ResponseWriter, r *http.Request) {
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("upgrade:", err)
return
}
defer func() {
log.Println("disconnect !!")
c.Close()
}()
for {
mtype, msg, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
break
}
log.Printf("receive: %s\n", msg)
err = c.WriteMessage(mtype, msg)
if err != nil {
log.Println("write:", err)
break
}
}
})
log.Println("server start at :8899")
log.Fatal(http.ListenAndServe(":8899", nil))
}
func main() {
c, _, err := websocket.DefaultDialer.Dial("ws://127.0.0.1:8899/echo", nil)
if err != nil {
log.Fatal("dial:", err)
}
defer c.Close()
err = c.WriteMessage(websocket.TextMessage, []byte("hello ithome30day"))
if err != nil {
log.Println(err)
return
}
_, msg, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
return
}
log.Printf("receive: %s\n", msg)
}
接下來只要依序啟動 server & client ,就可以開到 client 對 server 送了 hello ithome30day
,並且回覆相同字串給 client。完整範例在我的 github ,載下來就可以直接執行。